package com.frank.demo.service;/*
 *@author:xec
 *@date:2022/2/28  8:50
 */

import com.frank.demo.domain.Content;
import com.frank.demo.domain.Doc;
import com.frank.demo.domain.DocExample;
import com.frank.demo.exception.BusinessException;
import com.frank.demo.exception.BusinessExceptionCode;
import com.frank.demo.mapper.ContentMapper;
import com.frank.demo.mapper.DocMapper;
import com.frank.demo.mapper.MyDocMapper;
import com.frank.demo.req.DocQueryReq;
import com.frank.demo.req.DocSaveReq;
import com.frank.demo.resp.DocQueryResp;
import com.frank.demo.resp.PageResp;
import com.frank.demo.utils.CopyUtil;
import com.frank.demo.utils.RedisUtil;
import com.frank.demo.utils.RequestContext;
import com.frank.demo.utils.SnowFlake;
import com.frank.demo.websocket.WebSocketServer;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.slf4j.MDC;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;

import javax.annotation.Resource;
import java.util.List;

@Service
public class DocService {

    @Resource
    private DocMapper docMapper ;

    @Resource
    private SnowFlake snowFlake;

    @Resource
    private MyDocMapper myDocMapper;

    @Resource
    private ContentMapper contentMapper;

    @Resource
    RedisUtil redisUtil;

//    @Resource
//    WebSocketServer webSocketServer;

    @Resource
    WsService wsService;

    public List<DocQueryResp> getAll(){
        DocExample docExample = new DocExample();
        docExample.setOrderByClause("sort asc");
        List<Doc> docList = docMapper.selectByExample(docExample);
        List<DocQueryResp> respList = CopyUtil.copyList(docList,DocQueryResp.class);
        return respList;
    }

    public PageResp<DocQueryResp> getDoc(DocQueryReq docQueryReq){
        DocExample docExample = new DocExample();
        DocExample.Criteria criteria = docExample.createCriteria();

        // 需要注意的是，这行代码只对遇到的第一个select查询有用，因此在使用时，想对那个select分页就写在它的上一行
        PageHelper.startPage(docQueryReq.getPage(), docQueryReq.getSize());// 1代码从第几页查，3代表每页显示3条数据.
        List<Doc> docs = docMapper.selectByExample(docExample);
        // 这里查出来的是Doc，里面字段和表字段是一样的，但是我们返回出去的是响应封装类，因此要转化一下

        List<DocQueryResp> respList = CopyUtil.copyList(docs,DocQueryResp.class);
        PageInfo<Object> pageInfo = new PageInfo<>();
        PageResp pageResp = new PageResp();
        pageResp.setTotal(pageInfo.getTotal());
        pageResp.setList(respList);
        return pageResp;
    }

    /**
     * 更新和添加方法
     */
    @Transactional
    public void save(DocSaveReq req) {
        Doc doc = CopyUtil.copy(req, Doc.class);
        Content content = CopyUtil.copy(req,Content.class);
        if (ObjectUtils.isEmpty(req.getId())) {
            // 新增
            doc.setId(snowFlake.nextId());
            doc.setViewCount(0);  // 给阅读数设值默认为0
            doc.setVoteCount(0);
            docMapper.insert(doc);
            content.setId(doc.getId());
            contentMapper.insert(content);
        } else {
            // 更新
            docMapper.updateByPrimaryKey(doc);
            int result = contentMapper.updateByPrimaryKeyWithBLOBs(content);
            if (result==0){
                contentMapper.insert(content);
            }
        }
    }


    public void delete(Long id) {
        docMapper.deleteByPrimaryKey(id);
    }

    /**
     * 根据id集合进行批量删除
     * @param ids
     */
    public void delete(List<String> ids) {
        DocExample docExample = new DocExample();
        DocExample.Criteria criteria = docExample.createCriteria();
        criteria.andIdIn(ids);
        docMapper.deleteByExample(docExample);
    }

    /**
     * 查询文档内容
     * @param id
     * @return
     */
    public String findContent(Long id) {
        Content content = contentMapper.selectByPrimaryKey(id);
        myDocMapper.increaseViewCount(id);  // 更新阅读次数
        if (content != null){
            return  content.getContent();
        }
        return "";
    }

    /**
     * 根据电子书id查询文档
     * @param ebookId
     * @return
     */
    public List<DocQueryResp> getDocByEbookId(Long ebookId) {
        DocExample docExample = new DocExample();
        docExample.createCriteria().andEbookIdEqualTo(ebookId);
        docExample.setOrderByClause("sort asc");
        List<Doc> docList = docMapper.selectByExample(docExample);
        List<DocQueryResp> respList = CopyUtil.copyList(docList, DocQueryResp.class);
        return respList;
    }

    public void vote(Long id) {
//        myDocMapper.increaseVoteCount(id);
        String ip = RequestContext.getRemoteAddr();
        if (redisUtil.validateRepeat("DOC_VOTE_"+id+"_"+ip,5000)){
            myDocMapper.increaseVoteCount(id);
        }else {
            throw new BusinessException(BusinessExceptionCode.VOTE_REPEAT);
        }
        // 推送消息
//        Doc docDB = docMapper.selectByPrimaryKey(id);
//        String docName = docDB.getName();
//        String message = "【"+docName+"】"+"被点赞！";
//        webSocketServer.sendInfo(message);
        // 推送消息 （异步化）
        Doc docDB = docMapper.selectByPrimaryKey(id);
        String logId = MDC.get("LOG_ID");
        wsService.sendInfo("【"+docDB.getName()+"】"+"被点赞！",logId);
    }

    /**
     * 统计电子书阅读数，点赞数方法
     */
    public void updateEbookInfo(){
        myDocMapper.updateEbookInfo();
    }
}
